import { chat, type Message as ChatMessage } from '@/api/chat'
import { api } from '@/api/api'
import ErrorHandler from '@/utils/errorHandler'

export interface SendMessageRequest {
  sessionId: string
  content: string
  messages?: Array<{ role: 'user' | 'assistant' | 'system'; content: string }>
  chatConfig?: {
    model?: string
    temperature?: number
    maxTokens?: number
    topP?: number
    useRAG?: boolean
    useTools?: boolean
  }
  stream?: boolean
}

export interface SendMessageResponse {
  messageId: string
  content: string
  role: 'user' | 'assistant'
  timestamp: string
  sessionId: string
  references?: Array<{
    documentId: string
    content: string
    score: number
    pageNumber?: number
  }>
}

export interface StreamCallbacks {
  onChunk: (assistantId: string, fullContent: string) => void
  onComplete: (assistantId: string, fullResponse: string) => void
  onError: (assistantId: string, error: Error) => void
  onWarning?: (message: string) => void
}

type NormalizedMessage = ChatMessage

class ChatService {
  private ensuredSessions = new Set<string>()

  private buildMessages(request: SendMessageRequest): NormalizedMessage[] {
    if (request.messages && request.messages.length) {
      return request.messages
    }
    return [{ role: 'user', content: request.content }]
  }

  private normalizeSendResponse(request: SendMessageRequest, content: string): SendMessageResponse {
    return {
      messageId: `${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
      content,
      role: 'assistant',
      timestamp: new Date().toISOString(),
      sessionId: request.sessionId,
      references: []
    }
  }

  sendMessageWithCallbacks(
    request: SendMessageRequest & { assistantId: string },
    callbacks: StreamCallbacks,
    signal?: AbortSignal
  ): AbortController {
    let fullContent = ''
    let timeoutId: number | null = null

    const resetTimeout = () => {
      if (timeoutId) clearTimeout(timeoutId)
      timeoutId = window.setTimeout(() => {
        callbacks.onError(request.assistantId, new Error('流式响应超时，请稍后再试'))
      }, 60000)
    }

    const clearTimeoutSafe = () => {
      if (timeoutId) {
        clearTimeout(timeoutId)
        timeoutId = null
      }
    }

    const controller = chat(
      {
        sessionId: request.sessionId,
        messages: this.buildMessages(request),
        stream: true,
        chatConfig: request.chatConfig
      },
      {
        onChunk: (chunk) => {
          resetTimeout()
          fullContent += chunk
          callbacks.onChunk(request.assistantId, fullContent)
        },
        onComplete: () => {
          clearTimeoutSafe()
          callbacks.onComplete(request.assistantId, fullContent)
        },
        onWarning: (message) => {
          callbacks.onWarning?.(message)
          if (!callbacks.onWarning) {
            ErrorHandler.showWarning(message, '聊天')
          }
        },
        onError: (error) => {
          clearTimeoutSafe()
          callbacks.onError(request.assistantId, error)
        }
      },
      signal
    )

    resetTimeout()
    return controller
  }

  async sendMessage(
    request: SendMessageRequest,
    options?: { signal?: AbortSignal }
  ): Promise<SendMessageResponse> {
    if (request.stream) {
      return new Promise<SendMessageResponse>((resolve, reject) => {
        const assistantId = `${Date.now()}_${Math.random().toString(16).slice(2)}`
        let streamed = ''
        this.sendMessageWithCallbacks(
          { ...request, assistantId },
          {
            onChunk: (_id, full) => {
              streamed = full
            },
            onComplete: (_id, full) => resolve(this.normalizeSendResponse(request, full || streamed)),
            onError: (_id, error) => {
              ErrorHandler.handleError(error, '发送消息', 'auto')
              reject(error)
            },
            onWarning: (message) => ErrorHandler.showWarning(message, '聊天')
          },
          options?.signal
        )
      })
    }

    return new Promise<SendMessageResponse>((resolve, reject) => {
      chat(
        {
          sessionId: request.sessionId,
          messages: this.buildMessages(request),
          stream: false,
          chatConfig: request.chatConfig
        },
        {
          onChunk: (chunk) => {
            resolve(this.normalizeSendResponse(request, chunk))
          },
          onComplete: () => {
            // handled in onChunk
          },
          onError: (error) => {
            ErrorHandler.handleError(error, '发送消息', 'auto')
            reject(error)
          }
        },
        options?.signal
      )
    })
  }

  async getChatHistory(
    sessionId: string,
    params: { limit?: number; offset?: number } = {},
    options: { title?: string } = {}
  ): Promise<{ items: any[]; total: number }> {
    if (!sessionId) return { items: [], total: 0 }

    try {
      await this.ensureSessionExists(sessionId, options.title)
      const response = await api.get(`/v1/sessions/${sessionId}/messages`, {
        params: {
          limit: params.limit ?? 200,
          offset: params.offset ?? 0
        }
      })
      const payload = response.data
      const items =
        Array.isArray(payload?.items) || Array.isArray(payload?.messages)
          ? payload.items || payload.messages
          : Array.isArray(payload)
            ? payload
            : []
      const total =
        typeof payload?.total === 'number'
          ? payload.total
          : Array.isArray(items)
            ? items.length
            : 0
      return { items, total }
    } catch (error) {
      ErrorHandler.handleError(error, '获取聊天历史', 'auto')
      return { items: [], total: 0 }
    }
  }

  async saveMessage(sessionId: string, content: string, role: 'user' | 'assistant') {
    try {
      await this.ensureSessionExists(sessionId)
      const response = await api.post(`/v1/sessions/${sessionId}/messages`, { role, content })
      return response.data
    } catch (error) {
      ErrorHandler.handleError(error, '保存消息', 'auto')
      return null
    }
  }

  private async ensureSessionExists(sessionId: string, title?: string) {
    if (!sessionId || this.ensuredSessions.has(sessionId)) return

    try {
      await api.post('/v1/sessions', {
        id: sessionId,
        ...(title ? { title } : {})
      })
      this.ensuredSessions.add(sessionId)
    } catch (error: any) {
      const status = error?.response?.status
      if (status === 409 || status === 422) {
        this.ensuredSessions.add(sessionId)
        return
      }
      console.warn('确保会话存在失败:', error)
    }
  }
}

export default new ChatService()
